package com.xiaomaoguai.fcp.pre.kepler.trace.interceptor;

import com.xiaomaoguai.fcp.pre.kepler.trace.exception.JaegerException;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import javax.annotation.Resource;
import java.util.Collection;

/**
 * @author August.Zhang
 * @version v1.0.0
 * @date 2020/1/6 21:43
 * @since JDK 1.8
 */
@Slf4j
@Aspect
public class KeplerHandlerAspect {

	@Resource
	protected Tracer tracer;

	@Resource
	private HandlerInterceptorFactory handlerInterceptorFactory;

	@Around("execution(public * com.xiaomaoguai.fcp.pre.kepler.router.*..handle(..))")
	public Object aroundHandle(ProceedingJoinPoint pjp) throws Throwable {
		Collection<HandlerAroundInterceptor> handlerAroundInterceptors = handlerInterceptorFactory.getAllValues();
		for (HandlerAroundInterceptor interceptor : handlerAroundInterceptors) {
			if (interceptor.accept(pjp)) {
				Span span = null;
				Scope scope = null;
				Object result = null;
				try {
					String operationName = interceptor.getOperationName(pjp);
					span = tracer.buildSpan(operationName).start();
					scope = tracer.activateSpan(span);

					interceptor.beforeMethod(pjp, span);
					result = pjp.proceed();
					interceptor.afterMethod(pjp, span);

					return result;
				} catch (Exception e) {
					if (span != null) {
						span.log(ExceptionUtils.getStackTrace(e));
					}
					//如果是jaeger自己的异常的话，就不抛出，继续执行业务逻辑，如果是业务的异常就需要抛出，交给尾Handler处理
					if (e instanceof JaegerException) {
						if (result == null) {
							result = pjp.proceed();
						}
						return result;
					} else {
						throw e;
					}
				} finally {
					if (scope != null) {
						scope.close();
					}
					if (span != null) {
						span.finish();
					}
				}
			}
		}
		return pjp.proceed();
	}

}
